home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / hop / hop.c next >
C/C++ Source or Header  |  1995-05-03  |  28KB  |  1,042 lines

  1. /*
  2.  *    @(#) hop.c 1.3 93/11/02 MRINC
  3.  *
  4.  * MODIFICATION HISTORY
  5.  *    - created 30 Nov 1990 by Ron Record (rr@sco.com)
  6.  *      based upon an algorithm published in the Sep 86 Scientific American
  7.  *  - added arguments to select between sqrt(), sin(), log(), and linear
  8.  *    functions (original was sqrt()).
  9.  *
  10.  *  - Rewritten using X11 19 Apr 1993 by Ron Record (rr@sco.com)
  11.  */
  12. /*************************************************************************
  13.  *                                                                       *
  14.  *  Copyright (c) 1987-1993 Ronald Joe Record                            *
  15.  *                                                                       *
  16.  *  All rights reserved. No part of this program or publication may be   *
  17.  *  reproduced, transmitted, transcribed, stored in a retrieval system,  *
  18.  *  or translated into any language or computer language, in any form or *
  19.  *  by any means, electronic, mechanical, magnetic, optical, chemical,   *
  20.  *  biological, or otherwise, without the prior written permission of:   *
  21.  *                                                                       *
  22.  *      Ronald Joe Record (408) 458-3718                                 *
  23.  *      212 Owen St., Santa Cruz, California 95062 USA                   *
  24.  *                                                                       *
  25.  *************************************************************************/
  26.  
  27. #include "hop.h"
  28.  
  29. #define MAX_A 100.0
  30. #define MAX_B 100.0
  31. #define MAX_C 100.0
  32. #define MAX_S 4
  33. #define MIN_S 1
  34. #define MAX_P 4000
  35. #define MIN_P 100
  36. #define MAX_MISS 75
  37. #define NUM_MODES 6
  38. #define MAX_H_IND 5
  39. #define M_A 0.2
  40. #define M_B 0.8
  41.  
  42. int screenx, screeny, xcenter, ycenter, period, num, move;
  43. int hop_hue, width, height, numfreecols, maxcolor, next;
  44. int demo=0, histogram=0, domiss=0, sqflag=1, eflag=0, sinflag=0, Oflag=0;
  45. int bothflag=0, logflag=0, lflag=0, change=0, stop=0, stopping=1;
  46. int nummaps=1, delay=0, useroot=0, full=0, oflag=0, h_ind=0;
  47. int minhist, maxhist, diff;
  48. int **xy;
  49. long limit = 0;
  50. double scale, a, b, c, d, e, i_inc, j_inc; 
  51. double exponent = 0.5;
  52. char *outname;
  53.  
  54. /* routines declared in this file */
  55. void event_loop(), usage(), init_contexts(), rehist(), hopalong(), root_exit();
  56. void Clear(), print_help(), set_max_min(), freemem(), setupmem(), initialize();
  57. void redisplay(), resize(), save(), parseargs(), Getkey(), setparams();
  58. int get_hist_index();
  59. /* external routines used in this file */
  60. extern long lrand48();
  61. extern void FlushBuffer(), BufferPoint(), InitBuffer();
  62.  
  63. void
  64. freemem()
  65. {
  66.     static int i;
  67.  
  68.     for (i=0;i<=width;i++)
  69.         free(xy[i]);
  70.     free(xy);
  71. }
  72.  
  73. zeromem()
  74. {
  75.     static int i, j;
  76.  
  77.     diff = maxhist = 1; minhist = MAXINT;
  78.     for (i=0; i<width+1; i++)
  79.         for (j=0; j<height+1; j++)
  80.             xy[i][j] = 0;
  81. }
  82.  
  83. void
  84. setupmem()
  85. {
  86.     static int i, j;
  87.  
  88.     if ((xy=(int **)malloc((width+1)*sizeof(int *))) == (int **)NULL) {
  89.         printf("Error malloc'ing xy.\n");
  90.         exit (-1);
  91.     }
  92.     for (i=0;i<width+1;i++) {
  93.         if ((xy[i]=(int *)malloc((height+1)*sizeof(int)))==(int *)NULL){
  94.             printf("Error malloc'ing xy[%d].\n", i);
  95.             exit (-1);
  96.         }
  97.     }
  98.     zeromem();
  99. }
  100.  
  101. void
  102. set_max_min(n)
  103. int n;
  104. {
  105.     if (n > maxhist)
  106.         maxhist = n;
  107.     if (n < minhist)
  108.         minhist = n;
  109.     diff = maxhist - minhist;
  110. }
  111.  
  112. void
  113. hopalong()
  114. {
  115.     int miss;
  116.     double inext, jnext, dtmp;
  117.     extern double pow(), fabs(), sqrt(), sin(), log();
  118.  
  119.     miss = 0;
  120.     screenx = xcenter + i_inc * scale;
  121.     screeny = ycenter + j_inc * scale;
  122.  
  123.     if ((screenx < width) && (screeny <= height) && 
  124.         (screenx >= 0) && (screeny >= 0)) {
  125.         if (histogram) {
  126.             xy[screenx][screeny]++;
  127.             set_max_min(xy[screenx][screeny]);
  128.             hop_hue = get_hist_index(xy[screenx][screeny]) + STARTCOLOR;
  129.         }
  130.         BufferPoint(dpy,canvas,pixmap,Data_GC,&Points,hop_hue,screenx,screeny);
  131.         miss=0;
  132.     }
  133.     else
  134.         if (++miss > MAX_MISS)
  135.             if (domiss)
  136.                 return;
  137.     if (sqflag)
  138.         dtmp = sqrt(fabs(b*i_inc-c));
  139.     else if (eflag)
  140.         dtmp = pow(fabs(b*i_inc-c), exponent);
  141.     else if (sinflag) {
  142.         dtmp = fabs(b*i_inc-c);
  143.         dtmp = (dtmp / 100.0) * sin(dtmp);
  144.     }
  145.     else if (bothflag) {
  146.         dtmp = fabs(b*i_inc-c);
  147.         dtmp = sqrt(dtmp) * sin(dtmp);
  148.     }
  149.     else if (logflag) {
  150.         dtmp = fabs(b*i_inc-c) + 1.0;
  151.         dtmp = log(dtmp);
  152.     }
  153.     else if (lflag)
  154.         dtmp = fabs(b*i_inc-c) / 50.0;
  155.     inext = d + j_inc - (i_inc < 0 ? -1 : 1) * dtmp;
  156.     jnext = a - i_inc + (j_inc < 0 ? -1 : 1) * (e*j_inc);
  157.  
  158.     i_inc = inext;
  159.     j_inc = jnext;
  160. }
  161.  
  162. void
  163. setparams()
  164. {
  165.     extern double drand48();
  166.  
  167.     scale = MIN_S + (lrand48() % MAX_S);
  168.     period = MIN_P + (lrand48() % MAX_P);
  169.     if (change) {
  170.         switch (rand() % NUM_MODES) {
  171.         case '0':    sqflag = 1;
  172.             eflag = lflag = sinflag = logflag = bothflag = 0;
  173.             break;
  174.         case '1':    eflag=1; exponent=drand48();
  175.             sqflag = lflag = sinflag = logflag = bothflag = 0;
  176.             break;
  177.         case '2':    lflag = 1;
  178.             eflag = sqflag = sinflag = logflag = bothflag = 0;
  179.             break;
  180.         case '3':    sinflag = 1;
  181.             eflag = sqflag = lflag = logflag = bothflag = 0;
  182.             break;
  183.         case '4':    logflag = 1;
  184.             eflag = sqflag = sinflag = lflag = bothflag = 0;
  185.             break;
  186.         case '5':    bothflag = 1;
  187.             eflag = sqflag = sinflag = lflag = logflag = 0;
  188.             break;
  189.         case '?':
  190.             usage();
  191.             break;
  192.         }
  193.     }
  194.     if (sqflag || eflag) {
  195.         a = drand48() * MAX_A;
  196.         b = drand48() * MAX_B;
  197.         c = drand48() * MAX_C;
  198.     }
  199.     else if (sinflag) {
  200.         a = drand48() * (MAX_A / 5);
  201.         b = drand48() * (MAX_B / 10);
  202.         c = drand48() * (MAX_C / 5);
  203.     }
  204.     else if (bothflag) {
  205.         a = drand48() * (MAX_A / 10);
  206.         b = drand48() * (MAX_B / 10);
  207.         c = drand48() * (MAX_C / 10);
  208.     }
  209.     else if (logflag || lflag) {
  210.         a = drand48() * MAX_A;
  211.         b = MAX_A - a;
  212.         c = drand48() * MAX_C;
  213.     }
  214. }
  215.  
  216. void
  217. parseargs(ac, av)
  218. int ac;
  219. char *av[];
  220. {
  221.     register int c;
  222.     int aset=1, bset=1, cset=1, pset=1, sset=1;
  223.     extern int optind;
  224.     extern char *optarg;
  225.     extern double atof();
  226.     extern long atol();
  227.  
  228.     outname = "hop.ppm";
  229.     width = 0; height = 0;
  230.     while ((c = getopt(ac, av, "AFHLORSZmuC:D:E:a:b:c:d:e:h:l:o:p:s:w:"))!=EOF){
  231.         switch (c) {
  232.         case 'A':    lflag=0; eflag=0; sqflag=0; sinflag=0; bothflag=0;
  233.                 logflag=1;
  234.                 if (aset)
  235.                     a=10; 
  236.                 if (bset)
  237.                     b=5; 
  238.                 if (cset)
  239.                     c=15;
  240.                 if (pset)
  241.                     period=1000;
  242.                 break;
  243.         case 'C':
  244.             numwheels = atoi(optarg);
  245.             if (numwheels > MAXWHEELS)
  246.                 numwheels = MAXWHEELS;
  247.             if (numwheels < 0)
  248.                 numwheels = 0;
  249.             break;
  250.         case 'D':    demo++; domiss=1;     
  251.                 nummaps=atoi(optarg);
  252.                 break;
  253.         case 'E':    exponent=atof(optarg);    
  254.                 eflag=1; sqflag=0;
  255.                 break;
  256.         case 'F':    stopping = 0;
  257.                 break;
  258.         case 'H':    histogram++;
  259.                 break;
  260.         case 'L':    logflag=0; eflag=0; sqflag=0; sinflag=0; bothflag=0;
  261.                 lflag=1;
  262.                 if (aset)
  263.                     a=10; 
  264.                 if (bset)
  265.                     b=5; 
  266.                 if (cset)
  267.                     c=15;
  268.                 if (pset)
  269.                     period=1000;
  270.                 break;
  271.         case 'O': /* Use the default parameters and map */
  272.                 Oflag++;
  273.                 break;
  274.         case 'R': useroot++;
  275.                 break;
  276.         case 'S':    logflag=0; eflag=0; sqflag=0; lflag=0; bothflag=0;
  277.                 sinflag=1;
  278.                 if (aset)
  279.                     a=20; 
  280.                 if (bset)
  281.                     b=1; 
  282.                 if (cset)
  283.                     c=5;
  284.                 if (sset)
  285.                     scale=2.0;
  286.                 if (pset)
  287.                     period=1000;
  288.                 break;
  289.         case 'Z':    logflag=0; eflag=0; sqflag=0; lflag=0; sinflag=0;
  290.                 bothflag=1;
  291.                 if (aset)
  292.                     a=3; 
  293.                 if (bset)
  294.                     b=2; 
  295.                 if (cset)
  296.                     c=1;
  297.                 if (sset)
  298.                     scale=0.1;
  299.                 if (pset)
  300.                     period=1000;
  301.                 break;
  302.         case 'a':    a=atof(optarg); aset=0;    
  303.                 break;
  304.         case 'b':    b=atof(optarg);    bset=0; 
  305.                 break;
  306.         case 'c':    c=atof(optarg);    cset=0; 
  307.                 break;
  308.         case 'd':    d=atof(optarg);    
  309.                 break;
  310.         case 'e':    e=atof(optarg);    
  311.                 break;
  312.         case 'h':
  313.             height = atoi(optarg);
  314.             break;
  315.         case 'l':    limit=atol(optarg);    
  316.                 break;
  317.         case 'm':    domiss=1;        
  318.                 break;
  319.         case 'o':    outname = optarg;        
  320.                 break;
  321.         case 'p':    period=atoi(optarg);    
  322.                 pset=0;
  323.                 break;
  324.         case 's':    scale=atof(optarg);
  325.                 sset=0; 
  326.                 break;
  327.         case 'w':
  328.             width = atoi(optarg);
  329.             break;
  330.         case 'u':
  331.         case '?':    usage();        
  332.                 break;
  333.         }
  334.     }
  335.     if (sqflag && demo)
  336.         change=1;
  337. }
  338.  
  339. void
  340. usage()
  341. {
  342.     fprintf(stderr,"usage: hop [-ALSZDmu][-E#][-a#][-b#][-c#][-d#][-e#][-l#][-p#][-s#]\n");
  343.     fprintf(stderr,"[-w width][-h height]\n");
  344.     fprintf(stderr, "\tWhere a, b, c, d and e are the dynamical parameters\n");
  345.     fprintf(stderr,"\tl is the limit, p the period, and s the scale\n");
  346.     fprintf(stderr,"\tThe algorithm in hop is an iterated function system :\n");
  347.     fprintf(stderr,"\n\t\tinext = d + j - (i<0 ? -1:1) * sqrt(fabs(b*c-i))\n");
  348.     fprintf(stderr,"\t\tjnext = a - (j<0 ? -1:1) * (e*i)\n\n");
  349.     fprintf(stderr, "\t-D indicates run in demo mode\n");
  350.     fprintf(stderr, "\t-E# uses pow() rather than sqrt() (# must be < 0.9)\n");
  351.     fprintf(stderr, "\t-m turns on missing mode (exits after 50 misses)\n");
  352.     fprintf(stderr, "\t-A uses log() rather than sqrt()\n");
  353.     fprintf(stderr, "\t-L uses a linear map rather than sqrt()\n");
  354.     fprintf(stderr, "\t-S uses a sin() map rather than sqrt()\n");
  355.     fprintf(stderr, "\t-Z uses both sin() and sqrt()\n");
  356.     fprintf(stderr, "\t-u produces this message\n");
  357.     fprintf(stderr, "\tDefaults are a=80 b=40 c=60 d=0 e=0 E=0.5 p=1024 s=4\n");
  358.     fprintf(stderr, "\t-A defaults are a=10 b=5 c=15 p=1000 s=4\n");
  359.     fprintf(stderr, "\t-L defaults are a=10 b=5 c=15 p=1000 s=4\n");
  360.     fprintf(stderr, "\t-S defaults are a=20 b=1 c=5 p=1000 s=2\n");
  361.     fprintf(stderr, "\t-Z defaults are a=3 b=2 c=1 p=1000 s=0.1\n");
  362.     exit(1);
  363. }
  364.  
  365. void
  366. init_contexts()
  367. {
  368.     static int i;
  369.  
  370.     /*
  371.      * create default, writable, graphics contexts for the canvas.
  372.      */
  373.     Data_GC[0] = XCreateGC(dpy, DefaultRootWindow(dpy),
  374.         (unsigned long) NULL, (XGCValues *) NULL);
  375.     /* set the background to black */
  376.     XSetBackground(dpy,Data_GC[0],BlackPixel(dpy, screen));
  377.     /* set the foreground of the 0th context to black */
  378.     XSetForeground(dpy, Data_GC[0], BlackPixel(dpy, screen));
  379.     Data_GC[1] = XCreateGC(dpy, DefaultRootWindow(dpy),
  380.         (unsigned long) NULL, (XGCValues *) NULL);
  381.     /* set the background to black */
  382.     XSetBackground(dpy,Data_GC[1],BlackPixel(dpy, screen));
  383.     /* set the foreground of the 1st context to white */
  384.     XSetForeground(dpy, Data_GC[1], WhitePixel(dpy,  screen));
  385.     for (i=2; i<maxcolor; i++) {
  386.         Data_GC[i] = XCreateGC(dpy, DefaultRootWindow(dpy),
  387.             (unsigned long) NULL, (XGCValues *) NULL);
  388.         /* set the background to black */
  389.         XSetBackground(dpy,Data_GC[i],BlackPixel(dpy, screen));
  390.         /* set the foreground of the ith context to i */
  391.         XSetForeground(dpy, Data_GC[i], i);
  392.     }
  393. }
  394.  
  395. void
  396. Clear()
  397. {
  398.     XFillRectangle(dpy, pixmap, Data_GC[0], 0, 0, width, height);
  399.     XCopyArea(dpy, pixmap, canvas, Data_GC[0], 0, 0, width, height, 0, 0);
  400. }
  401.  
  402. void
  403. initialize()
  404. {
  405.     InitBuffer(&Points, maxcolor);
  406.     i_inc = j_inc = 0.0;
  407.     if (Oflag)
  408.         Oflag=0;
  409.     else
  410.         setparams();
  411.     Clear();
  412.     num = 1;
  413. }
  414.  
  415. #define x_str 10
  416.  
  417. void
  418. print_help() 
  419. {
  420.     static char str[80];
  421.     static int y_str, spacing;
  422.     static int ascent, descent, dir;
  423.     static XCharStruct overall;
  424.     static GC gc;
  425.  
  426.     gc = Data_GC[1];
  427.     XClearWindow(dpy, help);
  428.     y_str = 60;
  429.     sprintf(str,"During run-time, interactive control can be exerted via : ");
  430.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  431.     XQueryTextExtents(dpy,(XID)XGContextFromGC(gc),"Hey!",
  432.             4,&dir,&ascent,&descent,&overall);
  433.     spacing = ascent + descent + 5;
  434.     y_str += 2 * spacing;
  435.     sprintf(str,"        - lowers the value of mincolindex, + raises it");
  436.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  437.     y_str += spacing;
  438.     sprintf(str,"        f or F saves hop to a PPM file");
  439.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  440.     y_str += spacing;
  441.     sprintf(str,"        h or H or ? displays this message");
  442.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  443.     y_str += spacing;
  444.     sprintf(str,"        n goes on to the next hop");
  445.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  446.     y_str += spacing;
  447.     sprintf(str,"        N creates a new replacement hop");
  448.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  449.     y_str += spacing;
  450.     sprintf(str,"        r or s spins the colorwheel");
  451.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  452.     y_str += spacing;
  453.     sprintf(str,"        w decrements, W increments the color wheel index");
  454.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  455.     y_str += spacing;
  456.     sprintf(str,"        q or Q exits");
  457.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  458.     y_str += 2*spacing;
  459.     sprintf(str,"Press 'h', 'H', or '?' to unmap the help window");
  460.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  461. }
  462.  
  463. void
  464. redisplay (event)
  465. XExposeEvent    *event;
  466. {
  467.     if ((event->window == help) && (!useroot))
  468.         print_help();
  469.     else {
  470.         /*
  471.         * Extract the exposed area from the event and copy
  472.         * from the saved pixmap to the window.
  473.         */
  474.         XCopyArea(dpy, pixmap, canvas, Data_GC[0], event->x, event->y, 
  475.             event->width, event->height, event->x, event->y);
  476.     }
  477. }
  478.  
  479. void
  480. resize()
  481. {
  482.     Window r;
  483.     int j; 
  484.     int x, y;
  485.     unsigned int bw, d, new_w, new_h;
  486.  
  487.     XGetGeometry(dpy,canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
  488.     if (((int)new_w == width) && ((int)new_h == height)) {
  489.         return;
  490.     }
  491.     if (histogram)
  492.         freemem();
  493.     width = (int)new_w; height = (int)new_h;
  494.     if (pixmap)
  495.         XFreePixmap(dpy, pixmap);
  496.     pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), 
  497.             width, height, DefaultDepth(dpy, screen));
  498.     if (histogram)
  499.         setupmem();
  500.     next = 1;
  501.     stop = 0;
  502.     nummaps++;
  503.     initialize();
  504. }
  505.  
  506. Cleanup() {
  507.     if (histogram)
  508.         freemem();
  509.     XCloseDisplay(dpy);
  510. }
  511.  
  512. /* Store hop growth in PPM format */
  513. void
  514. save()
  515. {
  516.     FILE *outfile;
  517.     unsigned char c;
  518.     XImage *ximage;
  519.     static int i,j;
  520.     struct Colormap {
  521.         unsigned char red;
  522.         unsigned char green;
  523.         unsigned char blue;
  524.     };
  525.     struct Colormap *colormap=NULL;
  526.  
  527.     if ((colormap=
  528.         (struct Colormap *)malloc(sizeof(struct Colormap)*maxcolor))
  529.             == NULL) {
  530.         fprintf(stderr,"Error malloc'ing colormap array\n");
  531.         Cleanup();
  532.         exit(-1);
  533.     }
  534.     outfile = fopen(outname,"w");
  535.     if(!outfile) {
  536.         perror(outname);
  537.         Cleanup();
  538.         exit(-1);
  539.     }
  540.  
  541.     ximage=XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
  542.  
  543.     for (i=0;i<maxcolor;i++) {
  544.         colormap[i].red=(unsigned char)(Colors[i].red >> 8);
  545.         colormap[i].green=(unsigned char)(Colors[i].green >> 8);
  546.         colormap[i].blue =(unsigned char)(Colors[i].blue >> 8);
  547.     }
  548.     fprintf(outfile,"P%d %d %d\n",6,width,height);
  549.     fprintf(outfile,"%d\n",maxcolor-1);
  550.  
  551.     for (j=0;j<height;j++)
  552.         for (i=0;i<width;i++) {
  553.             c = (unsigned char)XGetPixel(ximage,i,j);
  554.             fwrite((char *)&colormap[c],sizeof colormap[0],1,outfile);
  555.         }
  556.     fclose(outfile);
  557.     free(colormap);
  558. }
  559.  
  560. int
  561. get_hist_index(n)
  562. int n;
  563. {
  564.     static double p;
  565.     extern double asin(), pow();
  566.  
  567.     if (h_ind == 0)
  568.         return(n % numfreecols);
  569.     else if (h_ind == 1)
  570.         return((int)(pow((double)(numfreecols-1),
  571.                 1.0-((double)(n-minhist)/(double)diff))));
  572.     else if (h_ind == 2) { 
  573.         /* two lines (0,0)-(M_A,m*M_B) and (A,m*M_B)-(1,m) */
  574.         p = (double)(n - minhist) / (double)diff;
  575.         if (p < M_A)
  576.             return((int)((numfreecols-1)*M_B*p/M_A));
  577.         else
  578.             return((int)((numfreecols-1)*(((1.0-M_B)*(p-1.0))+1.0)));
  579.     }
  580.     else if (h_ind == 3) {
  581.         p = (double)(n - minhist) / (double)diff;
  582.         return((int)((0.5 + (asin((p*2.0) - 1.0)/M_PI))*(numfreecols-1)));
  583.     }
  584.     else if (h_ind == 4)
  585.         return(n*(numfreecols-1)/maxhist);
  586.     else
  587.         return((n-minhist)*(numfreecols-1)/diff);
  588. }
  589.  
  590. void
  591. rehist()
  592. {
  593.     static int i, j;
  594.  
  595.     Clear();
  596.     minhist = MAXINT; maxhist = 1;
  597.     for (i=0; i<width; i++)
  598.         for (j=0; j<height; j++) {
  599.             if (xy[i][j])
  600.                 set_max_min(xy[i][j]);
  601.         }
  602.     if (maxhist == minhist)
  603.         diff = 1;
  604.     else
  605.         diff = maxhist - minhist;
  606.     if (diff < 0)
  607.         diff = 1;
  608.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  609.     for (i=0; i<width; i++)
  610.         for (j=0; j<height; j++) {
  611.             if (xy[i][j])
  612.                 BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, 
  613.                             get_hist_index(xy[i][j])+STARTCOLOR,i,j);
  614.         }
  615.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  616. }
  617.  
  618. void
  619. Getkey(event)
  620. XKeyEvent *event;
  621. {
  622.     char key;
  623.     static int spinning=0, spindir=0;
  624.     static XWindowAttributes attr;
  625.     extern void init_color(), write_cmap();
  626.  
  627.     if (XLookupString(event, (char *)&key, sizeof(key), (KeySym *)0,
  628.        (XComposeStatus *) 0) > 0)
  629.             switch (key) {
  630.                 case '\015': /*write out current colormap to $HOME/.<prog>map*/
  631.                     write_cmap(dpy,cmap,Colors,maxcolor,"hop","Hop");
  632.                     break;
  633.                 case '+': mincolindex += INDEXINC;
  634.                     if (mincolindex > maxcolor)
  635.                         mincolindex = 1;
  636.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  637.                             mincolindex,maxcolor,numwheels,"hop","Hop",0);
  638.                     break;
  639.                 case '-': mincolindex -= INDEXINC;
  640.                     if (mincolindex < 1)
  641.                         mincolindex = maxcolor - 1;
  642.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  643.                             mincolindex,maxcolor,numwheels,"hop","Hop",0);
  644.                     break;
  645.                 case 'a': /* use the log function with new parameters */
  646.                 case 'A':    lflag=0; eflag=0; sqflag=0; sinflag=0; bothflag=0;
  647.                     next = logflag=1;
  648.                     nummaps++;
  649.                     change=0;
  650.                     if (histogram) {
  651.                         freemem();
  652.                         setupmem();
  653.                     }
  654.                     initialize();
  655.                     break;
  656.                 case 'b': /* toggle infinite doily */
  657.                 case 'B': stopping = (!stopping);
  658.                     break;
  659.                 case 'c':
  660.                 case 'C': Clear();
  661.                     InitBuffer(&Points, maxcolor);
  662.                     num = 1;
  663.                     break;
  664.                 case 'd': delay -= 25; if (delay < 0) delay = 0; break;
  665.                 case 'D': delay += 25; break;
  666.                 case 'f':    /* save in PPM format file */
  667.                 case 'F': save(); break;
  668.                 case 'H': histogram = (!histogram);
  669.                     if (histogram)
  670.                         setupmem();
  671.                     else
  672.                         freemem();
  673.                     break;
  674.                 case 'j': /* randomly change the map */
  675.                 case 'J': next = 1;
  676.                     nummaps++;
  677.                     change=1;
  678.                     if (histogram) {
  679.                         freemem();
  680.                         setupmem();
  681.                     }
  682.                     initialize();
  683.                     break;
  684.                 case 'k': /* use the square root function with new parameters */
  685.                 case 'K': logflag=0; eflag=0; lflag=0; sinflag=0; bothflag=0;
  686.                     next = sqflag=1;
  687.                     nummaps++;
  688.                     change=0;
  689.                     if (histogram) {
  690.                         freemem();
  691.                         setupmem();
  692.                     }
  693.                     initialize();
  694.                     break;
  695.                 case 'l': /* use the linear function with new parameters */
  696.                 case 'L': logflag=0; eflag=0; sqflag=0; sinflag=0; bothflag=0;
  697.                     next = lflag=1;
  698.                     nummaps++;
  699.                     change=0;
  700.                     if (histogram) {
  701.                         freemem();
  702.                         setupmem();
  703.                     }
  704.                     initialize();
  705.                     break;
  706.                 case 'm': /* use the sin function with new parameters */
  707.                 case 'M':    logflag=0; eflag=0; sqflag=0; lflag=0; bothflag=0;
  708.                     next = sinflag=1;
  709.                     nummaps++;
  710.                     change=0;
  711.                     if (histogram) {
  712.                         freemem();
  713.                         setupmem();
  714.                     }
  715.                     initialize();
  716.                     break;
  717.                 case 'n':    /* go on to the next hop, same function */
  718.                     next = 1;
  719.                     change = 0;
  720.                     if (histogram) {
  721.                         freemem();
  722.                         setupmem();
  723.                     }
  724.                     initialize();
  725.                     break;
  726.                 case 'N':    /* go on to the next hop, different function */
  727.                     next = change = 1;
  728.                     if (histogram) {
  729.                         freemem();
  730.                         setupmem();
  731.                     }
  732.                     initialize();
  733.                     break;
  734.                 case 'r': h_ind--;
  735.                     if (h_ind < 0)
  736.                         h_ind = MAX_H_IND;
  737.                     if (histogram) rehist();
  738.                     break;
  739.                 case 'R': h_ind++;
  740.                     if (h_ind > MAX_H_IND)
  741.                         h_ind = 0;
  742.                     if (histogram) rehist();
  743.                     break;
  744.                 case 'S': spinning=0;
  745.                     break;
  746.                 case 's': spinning=1; spindir=(!spindir);
  747.                     Spin(dpy,cmap,Colors,STARTCOLOR,maxcolor,delay,spindir);
  748.                     break;
  749.                 case '\027': /* (ctrl-W) read palette from $HOME/.hopmap */
  750.                   numwheels = 0;
  751.                   init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  752.                             mincolindex,maxcolor,numwheels,"hop","Hop",0);
  753.                   break;
  754.                 case 'W': 
  755.                     if (numwheels < MAXWHEELS)
  756.                         numwheels++;
  757.                     else
  758.                         numwheels = 0;
  759.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  760.                             mincolindex,maxcolor,numwheels,"hop","Hop",0);
  761.                     break;
  762.                 case 'w': 
  763.                     if (numwheels > 0)
  764.                         numwheels--;
  765.                     else
  766.                         numwheels = MAXWHEELS;
  767.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  768.                             mincolindex,maxcolor,numwheels,"hop","Hop",0);
  769.                     break;
  770.                 case '?':
  771.                 case 'h': 
  772.                     if (!useroot) {
  773.                         XGetWindowAttributes(dpy, help, &attr);
  774.                         if (attr.map_state != IsUnmapped)
  775.                             XUnmapWindow(dpy, help);
  776.                         else {
  777.                             XMapRaised(dpy, help);
  778.                             print_help();
  779.                         }
  780.                     }
  781.                     break;
  782.                 case 'X':    /* create new hops, erasing the old */
  783.                         next = stop = 1;
  784.                         nummaps++;
  785.                         FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  786.                                         0, maxcolor);
  787.                         initialize();
  788.                         if (histogram) {
  789.                             freemem();
  790.                             setupmem();
  791.                         }
  792.                         break;
  793.                 case 'y': /* use known ok parameters with the sqrt function */
  794.                 case 'Y':    logflag=0; eflag=0; bothflag=0; lflag=0; sinflag=0;
  795.                     next = sqflag=1;
  796.                     nummaps++;
  797.                     scale = 1.0;
  798.                     period = 1024;
  799.                     a = 80.0; b = 40.0; c = 60.0; d = 0.0; e = 0.0;
  800.                     i_inc = j_inc = 0.0;
  801.                     InitBuffer(&Points, maxcolor);
  802.                     if (histogram) {
  803.                         freemem();
  804.                         setupmem();
  805.                     }
  806.                     Clear();
  807.                     num = 1;
  808.                     break;
  809.                 case 'z': /* use sqrt & sin functions with new parameters */
  810.                 case 'Z':    logflag=0; eflag=0; sqflag=0; lflag=0; sinflag=0;
  811.                     next = bothflag=1;
  812.                     nummaps++;
  813.                     change=0;
  814.                     if (histogram) {
  815.                         freemem();
  816.                         setupmem();
  817.                     }
  818.                     initialize();
  819.                     break;
  820.                 case 'Q':
  821.                 case 'q': Cleanup(); exit(0); break;
  822.             }
  823.             if (spinning)
  824.                 Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, spindir);
  825. }
  826.  
  827. void
  828. event_loop()
  829. {
  830.     int n;
  831.     XEvent event;
  832.  
  833.     n = XEventsQueued(dpy, QueuedAfterFlush);
  834.     while (n-- > 0) {
  835.         XNextEvent(dpy, &event);
  836.         switch(event.type) {
  837.             case KeyPress:
  838.                 Getkey(&event);
  839.                 break;
  840.             case Expose:
  841.                 redisplay(&event);
  842.                 break;
  843.             case ConfigureNotify:
  844.                 resize();
  845.                 break;
  846.         }
  847.     }
  848. }
  849.  
  850. void
  851. root_exit() 
  852. {
  853.     static int i;
  854.  
  855.     if (histogram) {
  856.         h_ind = 2;
  857.         rehist();
  858.     }
  859.     XSetWindowBackgroundPixmap(dpy, canvas, pixmap);
  860.     for (i=0; i<maxcolor; i++)
  861.         XFreeGC(dpy, Data_GC[i]);
  862.     XFreePixmap(dpy, pixmap);
  863.     XClearWindow(dpy, canvas);
  864.     XFlush(dpy);
  865.         Cleanup();
  866.     exit(0);
  867. }
  868.  
  869. main(argc,argv)
  870. int argc;
  871. char *argv[];
  872. {
  873.     static int i, j;
  874.     static int count;
  875.     XSizeHints hint;
  876.     Atom __SWM_VROOT = None;
  877.     Window rootReturn, parentReturn, *children;
  878.     unsigned int numChildren;
  879.     extern void srand48(), init_color();
  880.     
  881.     i_inc = j_inc = 0.0;
  882.     scale = 1.0;
  883.     period = 1024;
  884.     a = 80.0; b = 40.0; c = 60.0; d = 0.0; e = 0.0;
  885.     parseargs(argc,argv);
  886.     srand48((long)time(0));
  887.     dpy = XOpenDisplay("");
  888.     screen = DefaultScreen(dpy);
  889.     if (useroot) {
  890.         nummaps = 1;
  891.         signal(SIGINT, root_exit);
  892.     }
  893.     if (full || useroot) {
  894.         width = XDisplayWidth(dpy, screen);
  895.         height = XDisplayHeight(dpy, screen);
  896.     }
  897.     if (width == 0)
  898.         width = XDisplayWidth(dpy, screen);
  899.     if (height == 0)
  900.         height = XDisplayHeight(dpy, screen);
  901.     xcenter = width / 2;
  902.     ycenter = height / 2;
  903.     if (limit == 0)
  904.         limit = width * height;
  905.     if (histogram)
  906.         setupmem();
  907.     maxcolor  = (int)XDisplayCells(dpy, screen);
  908.     if (maxcolor <= 16) {
  909.         STARTCOLOR = 2; delay = 100;
  910.         INDEXINC = 1; mincolindex = 5;
  911.     }
  912.     maxcolor = Min(maxcolor, MAXCOLOR);
  913.     numfreecols = maxcolor - STARTCOLOR;
  914.     hop_hue = STARTCOLOR;
  915.     /*
  916.     * Create the pixmap to hold the hop growth
  917.     */
  918.     pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height, 
  919.                            DefaultDepth(dpy, screen));
  920.     /*
  921.     * Create the window to display the hop pattern
  922.     */
  923.     hint.x = 0;
  924.     hint.y = 0;
  925.     hint.width = width;
  926.     hint.height = height;
  927.     hint.flags = PPosition | PSize;
  928.     if (useroot) {
  929.         canvas = DefaultRootWindow(dpy);
  930.         /* search for virtual root (from ssetroot by Tom LaStrange) */
  931.         __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
  932.         XQueryTree(dpy,canvas,&rootReturn,&parentReturn,&children,&numChildren);
  933.         for (j = 0; j < numChildren; j++) {
  934.             Atom actual_type;
  935.             int actual_format;
  936.             long nitems, bytesafter;
  937.             Window *newRoot = NULL;
  938.  
  939.             if (XGetWindowProperty (dpy, children[j], __SWM_VROOT,0,1, False, 
  940.                 XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
  941.                 (unsigned char **) &newRoot) == Success && newRoot) {
  942.                 canvas = *newRoot;
  943.                 break;
  944.             }
  945.         }
  946.     }
  947.     else {
  948.         canvas = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  949.             0, 0, width, height, 5, 0, 1);
  950.         XSetStandardProperties(dpy, canvas, "Hop by Ron Record",
  951.             "Hop", None, argv, argc, &hint);
  952.         XMapRaised(dpy, canvas);
  953.     }
  954.     XChangeProperty(dpy, canvas, XA_WM_CLASS, XA_STRING, 8, PropModeReplace, 
  955.                     "hop", strlen("hop"));
  956.     /*
  957.     * Create the window used to display the help info (if not running on root)
  958.     */
  959.     if (!useroot) {
  960.         hint.x = XDisplayWidth(dpy, screen) / 4;
  961.         hint.y = XDisplayHeight(dpy, screen) / 4;
  962.         hint.width = hint.x * 2;
  963.         hint.height = hint.y * 2;
  964.         help = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  965.                 hint.x, hint.y, hint.width, hint.height, 5, 0, 1);
  966.         XSetWindowBackground(dpy, help, BlackPixel(dpy, screen));
  967.         /* Title */
  968.         XSetStandardProperties(dpy,help,"Help","Help",None,argv,argc,&hint);
  969.         /* Try to write into a new color map */
  970.         cmap = XCreateColormap(dpy,canvas,DefaultVisual(dpy,screen),AllocAll);
  971.         init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex, maxcolor,
  972.                 numwheels,"hop", "Hop", 0);
  973.         /* install new color map */
  974.         XSetWindowColormap(dpy, canvas, cmap);
  975.         XSetWindowColormap(dpy, help, cmap);
  976.     }
  977.     init_contexts();
  978.     if (useroot)
  979.         XSelectInput(dpy,canvas,ExposureMask);
  980.     else {
  981.         XSelectInput(dpy,canvas,KeyPressMask|ExposureMask|StructureNotifyMask);
  982.         XSelectInput(dpy,help,KeyPressMask|ExposureMask);
  983.     }
  984.     for (i=0; i!=nummaps; i++) {
  985.         next = 0;
  986.         if (!stop)    /* true 1st time thru */
  987.             initialize();
  988.         stop=0;
  989.         if (!histogram)
  990.             FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,hop_hue,hop_hue+1);
  991.         for (;;) {
  992.             event_loop();
  993.             hopalong();
  994.             if (stop)
  995.               break;
  996.             if ((num % period) == 0) {
  997.                 if (histogram)
  998.                       FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,0,maxcolor);
  999.                 else {
  1000.                       FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,
  1001.                             hop_hue,hop_hue+1);
  1002.                       hop_hue++; 
  1003.                       if (hop_hue >= maxcolor)
  1004.                         hop_hue = STARTCOLOR;
  1005.                 }
  1006.             }
  1007.             if ((++num > limit) && stopping)
  1008.                 stop = 1;
  1009.         }
  1010.         FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,0,maxcolor);
  1011.         if (oflag)
  1012.             save();
  1013.         if (demo) {
  1014.             event_loop();
  1015.             DemoSpin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 4);
  1016.             event_loop();
  1017.             for (j=0; j<=MAXWHEELS; j++) {
  1018.                 init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex, 
  1019.                         maxcolor, j, "hop", "Hop", 0);
  1020.                 event_loop();
  1021.                 sleep(1);
  1022.             }
  1023.         }
  1024.         else if (useroot)
  1025.             root_exit();
  1026.         else {
  1027.             XSync(dpy, True);
  1028.             Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 0);
  1029.             for (;;) {
  1030.                 event_loop();
  1031.                 if (next) break;
  1032.             }
  1033.             if (histogram) {
  1034.                 freemem();
  1035.                 setupmem();
  1036.             }
  1037.         }
  1038.     }
  1039.     Cleanup();
  1040.     exit(0);
  1041. }
  1042.